﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Configuration;
using System.Diagnostics;
using System.Text.RegularExpressions;
using SevenZip;
using System.Windows.Forms.VisualStyles;

namespace WSBackup
{
    public partial class FormMain : Form
    {
        private const string DirectoryImageKey = "*";
        private const string FileImageKey = "-";
        //private readonly string RootPath = @"C:\WSBackup\WSBackupDST";
        private string _selectedDestPath;
        private string _selectedSrcPath;
        private readonly ListViewColumnSorter lvwColumnSorter;
        //private readonly Icon fileIconSmall;
        //private readonly Icon fileIconLarge;
        private readonly WSSettingsXml settings;
        private BackgroundWorker backgroundWorker1;

        private string currentFile;
        private DateTime g_dtStart;
        private int g_nTotalCount;
        private int g_nCount;

        FormProgress progressForm;

        public FormMain()
        {
            InitializeComponent();

            settings = WSSettingsXml.Load();

            //var s = settingsXml.Paths[0];
            //s.ExcludeType = ExcludeType.Include;
            //s.Extensions = new List<string> { "cs", "txt" };

            //settingsXml.Paths.Add(new WSArchiveConfig { DestPath = @"C:\WSBackup\WSBackupDST", SrcPath = @"C:\WSBackup\WSBackupSRC" });
            //settingsXml.Paths.Add(new WSArchiveConfig { DestPath = @"E:\WSBackup\Documents", SrcPath = @"C:\Users\pagac\Documents" });
            //settingsXml.Exclude = "Pokus";
            //settingsXml.Save();

            //var settings = WSSettings.Load();
            //settings.paths.Add(new WSArchiveConfig { DestParth = @"C:\WSBackup\WSBackupDST", SrcPath = @"C:\WSBackup\WSBackupSRC" });
            //settings.paths.Add(new WSArchiveConfig { DestParth = @"E:\WSBackup\Documents", SrcPath = @"C:\Users\pagac\Documents" });
            //settings.Save();

            this.listViewFiles.ListViewItemSorter = lvwColumnSorter = new ListViewColumnSorter();

            FillPaths();
            InitImages();

            toolStripStatusLabel1.Text = string.Empty;
            toolStripStatusLabel2.Text = string.Empty;

        }

        private void InitImages()
        {
            imageListSmall.Images.Clear();
            imageListLarge.Images.Clear();

            var fileIconSmall = IconTools.GetIconForExtension(@"C:\Windows\System32\imageres.dll,-4", ShellIconSize.SmallIcon, false);
            var fileIconLarge = IconTools.GetIconForExtension(@"C:\Windows\System32\imageres.dll,-4", ShellIconSize.LargeIcon, false);

            imageListSmall.Images.Add(DirectoryImageKey, fileIconSmall);
            imageListLarge.Images.Add(DirectoryImageKey, fileIconLarge);

            fileIconSmall = IconTools.GetIconForExtension(@"C:\Windows\System32\imageres.dll,-2", ShellIconSize.SmallIcon, false);
            fileIconLarge = IconTools.GetIconForExtension(@"C:\Windows\System32\imageres.dll,-2", ShellIconSize.LargeIcon, false);

            imageListSmall.Images.Add(FileImageKey, fileIconSmall);
            imageListLarge.Images.Add(FileImageKey, fileIconLarge);
        }

        private void ListDirectory1(TreeView treeView, string path)
        {
            treeView.Nodes.Clear();
            listViewFiles.Items.Clear();

            TreeNode node;
            var rootDirectory = new DirectoryInfo(path);
            if (rootDirectory.Exists)
            {
                node = CreateTreeNode(rootDirectory);
            }
            else
            {
                node = new TreeNode(rootDirectory.Name + "!") { ImageIndex = 1, SelectedImageIndex = 1 };
            }

            treeView.Nodes.Add(node);
            treeView.SelectedNode = node;

            //if (NeedConversion(false))
            //{
            //    tsbBackup2.Enabled = false;
            //}

        }

        private TreeNode CreateTreeNode(DirectoryInfo di)
        {
            var files = di.GetFiles("*.bck*").Where(s => s.Extension == ".bck" || s.Extension == ".bck7z" || s.Extension == ".bck7zip").Count();
            var dirs = di.GetDirectories().Length;

            var node = new TreeNode(di.Name + " (" + dirs + "/" + files + ")") { Tag = di.FullName };
            if (dirs > 0)
            {
                node.Nodes.Add("?");
            }

            return node;
        }

        private void ReadFolder()
        {
            listViewFiles.BeginUpdate();
            listViewFiles.Items.Clear();

            //var iconForFile = SHGetFileInfo.GetFileIcons(SelectedPath);
            //if (iconForFile != null)
            //{
            //    imageListSmall.Images.Add(DirectoryImageKey, iconForFile.IconSmall);
            //    imageListLarge.Images.Add(DirectoryImageKey, iconForFile.IconLarge);
            //}

            var diDest = new DirectoryInfo(SelectedDstPath);

            if (SelectedDstPath != currentPath.DestPath && diDest.Parent != null)
            {
                var fi = new FileListViewItem { IsDirectory = true, FileName = diDest.Parent.FullName };
                var item = new ListViewItem { Text = "..", Tag = fi, ImageKey = DirectoryImageKey };
                item.SubItems.Add("");
                item.SubItems.Add("");
                listViewFiles.Items.Add(item);
            }

            foreach (var directory in diDest.GetDirectories())
            {
                if (directory.Name.Equals(".Bck7z", StringComparison.InvariantCultureIgnoreCase))
                    continue;

                var fi = new FileListViewItem { IsDirectory = true, FileName = directory.FullName };
                var item = new ListViewItem { Text = directory.Name, Tag = fi, ImageKey = DirectoryImageKey };
                item.SubItems.Add(string.Empty);
                item.SubItems.Add(CreateSubItem(directory.LastWriteTime));

                if ((directory.Attributes & FileAttributes.Hidden) != 0)
                {
                    item.ForeColor = Color.Silver;
                }
                else
                {
                    var src = ConvertDstPathToSrc(fi);
                    if (!Directory.Exists(src))
                        item.ForeColor = Color.Red;
                }
                listViewFiles.Items.Add(item);
            }

            foreach (var file in diDest.GetFiles("*.bck*").Where(s => s.Extension == ".bck" || s.Extension == ".bck7z" || s.Extension == ".bck7zip"))
            {
                var fi = new FileListViewItem { IsDirectory = false, FileName = file.FullName };
                var filename = file.Name.Substring(0, file.Name.Length - file.Extension.Length);
                var item = new ListViewItem { Text = filename, Tag = fi };
                var pos = filename.LastIndexOf('.');
                var extension = pos >= 0 ? filename.Substring(pos) : string.Empty;

                // Check to see if the image collection contains an image 
                // for this extension, using the extension as a key. 
                if (!imageListSmall.Images.ContainsKey(extension))
                {
                    var icon = IconTools.GetIconForExtension(extension, ShellIconSize.SmallIcon);
                    if (icon == null)
                    {
                        extension = FileImageKey;
                    }
                    else
                    {
                        imageListSmall.Images.Add(extension, icon);
                    }

                    icon = IconTools.GetIconForExtension(extension, ShellIconSize.LargeIcon);
                    if (icon == null)
                    {
                        extension = FileImageKey;
                    }
                    else
                    {
                        imageListLarge.Images.Add(extension, icon);
                    }

                    /*
                    // If not, add the image to the image list.
                    iconForFile = SHGetFileInfo.GetFileIcons(file.FullName);
                    if (iconForFile != null)
                    {
                        imageListSmall.Images.Add(file.Extension, iconForFile.IconSmall);
                        imageListLarge.Images.Add(file.Extension, iconForFile.IconLarge);
                    } 
                    */
                }
                item.ImageKey = extension;
                item.SubItems.Add(CreateSubItem(file.Length));
                item.SubItems.Add(CreateSubItem(file.LastWriteTime));

                if (!File.Exists(SelectedSrcPath + "\\" + filename))
                    item.ForeColor = Color.Red;
                listViewFiles.Items.Add(item);
            }
            listViewFiles.EndUpdate();


        }

        private ListViewItem.ListViewSubItem CreateSubItem(object o)
        {
            if (o is Int64)
                return new ListViewItem.ListViewSubItem() { Text = ((Int64)o).ToString("#,##0"), Tag = o };

            if (o is DateTime)
                return new ListViewItem.ListViewSubItem() { Text = ((DateTime)o).ToString("dd.MM.yyyy HH:mm:ss"), Tag = o };

            return new ListViewItem.ListViewSubItem() { Text = o.ToString(), Tag = o };
        }

        private void detailToolStripMenuItem_Click(object sender, EventArgs e)
        {
            listViewFiles.View = View.Details;
            detailToolStripMenuItem.Checked = true;
            largeIconsToolStripMenuItem.Checked = false;
        }

        private void largeIconsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            listViewFiles.View = View.LargeIcon;
            largeIconsToolStripMenuItem.Checked = true;
            detailToolStripMenuItem.Checked = false;
        }

        private void listView1_DoubleClick(object sender, EventArgs e)
        {
            if (listViewFiles.SelectedItems.Count >= 1)
            {
                var items = listViewFiles.SelectedItems;
                var fi = items[0].Tag as FileListViewItem;
                if (fi.IsDirectory)
                {
                    Cursor = Cursors.WaitCursor;
                    TreeNode itemNode = null;
                    if (items[0].Text == "..")
                    {
                        itemNode = treeViewFolders.SelectedNode.Parent;
                    }
                    else
                    {
                        itemNode = FromID(fi.FileName, treeViewFolders.SelectedNode);
                    }
                    if (itemNode != null)
                    {
                        treeViewFolders.SelectedNode = itemNode;
                    }
                    SelectedDstPath = fi.FileName;
                    Cursor = Cursors.Default;
                }
                else
                {
                    new FormRevisions(settings, SelectedSrcPath, fi.FileName).ShowDialog(this);
                }
            }
        }

        string SelectedDstPath
        {
            get
            {
                return this._selectedDestPath;
            }
            set
            {
                this._selectedDestPath = value;
                //TODO Zment cestu podla skutocneho nastavenia 
                // return value.Length <= length ? value : value.Substring(value.Length - length);
                this._selectedSrcPath = currentPath.SrcPath + this._selectedDestPath.Substring(currentPath.DestPath.Length);
                toolStripStatusLabel1.Text = _selectedDestPath;
                ReadFolder();
            }
        }

        string SelectedSrcPath
        {
            get
            {
                return this._selectedSrcPath;
            }
        }

        public TreeNode FromID(object value, TreeNode rootNode)
        {
            foreach (TreeNode node in rootNode.Nodes)
            {
                if (node.Tag != null && node.Tag.Equals(value))
                    return node;
                /*
                TreeNode next = FromID(value, node);
                if (next != null) 
                    return next; 
                */
            }
            return null;
        }

        private void listView1_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            // Determine if clicked column is already the column that is being sorted.
            if (e.Column == lvwColumnSorter.SortColumn)
            {
                // Reverse the current sort direction for this column.
                this.lvwColumnSorter.Order = this.lvwColumnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;
            }
            else
            {
                // Set the column number that is to be sorted; default to ascending.
                lvwColumnSorter.SortColumn = e.Column;
                lvwColumnSorter.Order = SortOrder.Ascending;
            }

            for (var i = 0; i < listViewFiles.Columns.Count; i++)
            {
                ListViewColumnHeaderHelper.SetColumnHeaderSortIcon(listViewFiles, i, i == lvwColumnSorter.SortColumn ? lvwColumnSorter.Order : SortOrder.None);
            }

            // Perform the sort with these new sort options.
            //this.listView1.ListViewItemSorter = new ListViewItemComparer(e.Column);
            this.listViewFiles.Sort();
        }

        private void tsbRefresh_Click(object sender, EventArgs e)
        {
            InitImages();
            ReadFolder();
        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            SelectedDstPath = (string)e.Node.Tag;
        }

        private void cmbArchive_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cmbArchive.SelectedItem != null)
            {
                var item = (WSArchiveConfig)cmbArchive.SelectedItem;
                ListDirectory1(treeViewFolders, item.DestPath);
                settings.LastArchive = currentPath.Name;
            }
        }

        private WSArchiveConfig currentPath
        {
            get
            {
                if (cmbArchive.SelectedItem != null)
                {
                    return (WSArchiveConfig)cmbArchive.SelectedItem;
                }
                return null;
            }
        }

        private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            if (e.Node.Nodes.Count == 1 && e.Node.Nodes[0].Text == "?")
            {
                e.Node.Nodes.Clear();
                var directoryInfo = new DirectoryInfo((string)e.Node.Tag);
                foreach (var directory in directoryInfo.GetDirectories())
                {
                    if (!directory.Name.Equals(".Bck7z", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var childDirectoryNode = CreateTreeNode(directory);
                        e.Node.Nodes.Add(childDirectoryNode);
                    }
                }
            }

        }

        private static void IncrementDict(Dictionary<string, int> dict, string key)
        {
            if (dict.ContainsKey(key))
            {
                dict[key]++;
            }
            else
            {
                dict.Add(key, 1);
            }
        }

        private static void WriteStatistics(StringBuilder sb, string label, Dictionary<string, int> dict)
        {
            sb.AppendFormat("\r\n{0}: {1}\r\n", label, dict.Sum(x => x.Value));
            foreach (var s in dict.OrderBy(x => x.Key))
            {
                sb.AppendFormat(" {0} {1}\r\n", s.Key, s.Value);
            }
        }

        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (currentPath != null)
            {
                settings.LastArchive = currentPath.Name;
                settings.Save();
            }
        }

        private void FormMain_KeyDown(object sender, KeyEventArgs e)
        {
            if (!e.Shift && !e.Alt && !e.Control && e.KeyCode == Keys.F5)
            {
                tsbRefresh_Click(sender, null);
            }
        }

        private void tsbOptions_Click(object sender, EventArgs e)
        {
            var frm = new FormOptions(settings);
            if (frm.ShowDialog() == DialogResult.OK)
            {
                settings.Save();
                FillPaths();
            }
        }

        private void tsbBackup2_Click(object sender, EventArgs e)
        {

            g_nTotalCount = 0;
            g_nCount = 0;

            var ProgressCaption = string.Empty;

            backgroundWorker1 = new BackgroundWorker();
            backgroundWorker1.WorkerReportsProgress = true;
            backgroundWorker1.WorkerSupportsCancellation = true;
            backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);

            var convert = NeedConversion();
            if (convert > 0)
            {
                if (MessageBox.Show(this, "Repozitory obsahuje " + convert.ToString("N0") + " suborov, ktore su v starom formate. Subory je potrebne najskor skonvertovat do noveho formatu.\n\nMozem ho skonvertovat teraz?", "Staré repozitory", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != DialogResult.Yes)
                    return;
                backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork_Convert);
                ProgressCaption = "of Conversion " + currentPath.SrcPath;
            }
            else
            {
                backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork_Backup);
                ProgressCaption = "of Backup " + currentPath.SrcPath;
            }

            // create a new instance of the progress form
            progressForm = new FormProgress(ProgressCaption);

            // event handler for the Cancel button in progress form
            progressForm.Canceled += new EventHandler<EventArgs>(buttonCancel_Click);

            // Start the asynchronous operation.
            backgroundWorker1.RunWorkerAsync(currentPath);

            progressForm.ShowDialog();


        }

        // This event handler cancels the backgroundworker, fired from Cancel button in ProgresstForm.
        private void buttonCancel_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.WorkerSupportsCancellation)
            {
                // Cancel the asynchronous operation.
                backgroundWorker1.CancelAsync();
            }
        }

        // This event handler is where the time-consuming work is done.
        private void backgroundWorker1_DoWork_Backup(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            var nextOutputTime = g_dtStart = DateTime.Now;
            var errorlist = new List<KeyValuePair<string, string>>();
            var dictExcludedExtensions = new Dictionary<string, int>();
            var dictIncludedExtensions = new Dictionary<string, int>();
            var dictBackupedExtensions = new Dictionary<string, int>();
            //var dictCompressExtension = new string[] { ".rar", ".zip", ".7z", ".tar", ".jpg" };

            WSArchiveConfig config = (WSArchiveConfig)e.Argument;

            var wildcard = new FileWildcard(config.Extensions.ToList(), RegexOptions.IgnoreCase | RegexOptions.Compiled);

            var directoryQueue = new Queue<DirectoryInfo>();

            directoryQueue.Enqueue(new DirectoryInfo(config.SrcPath));

            while (directoryQueue.Count > 0)
            {
                var current = directoryQueue.Dequeue();
                try
                {
                    foreach (var d in current.GetDirectories())
                    {
                        directoryQueue.Enqueue(d);
                    }

                    if (worker.CancellationPending)
                    {
                        e.Cancel = true;
                        break;
                    }

                    foreach (var f in current.GetFiles())
                    {

                        if (worker.CancellationPending)
                        {
                            e.Cancel = true;
                            break;
                        }

                        if (f.Length > 107374182400) // 1 GB
                            continue;

                        currentFile = current.FullName + "\\" + f.Name;

                        if (DateTime.Now >= nextOutputTime)
                        {
                            ProgressAsync(string.Empty);
                            nextOutputTime = nextOutputTime.AddMilliseconds(250);
                        }
                        g_nTotalCount++;

                        var ext = f.Extension.ToLowerInvariant();
                        if (config.ExcludeType == ExcludeType.Exclude)
                        {
                            if (wildcard.IsMatch(ext))
                            {
                                IncrementDict(dictExcludedExtensions, ext);
                                continue;
                            }
                        }
                        else if (config.ExcludeType == ExcludeType.Include)
                        {
                            if (!wildcard.IsMatch(ext))
                            {
                                IncrementDict(dictExcludedExtensions, ext);
                                continue;
                            }
                        }

                        IncrementDict(dictIncludedExtensions, ext);

                        var archiveFileName = config.DestPath + f.FullName.Substring(config.SrcPath.Length);

                        var bck_ext = new[] { ".bck", ".bck7z", ".bck7zip" };
                        int i = bck_ext.Length - 1;
                        while (i >= 0)
                        {
                            var af = archiveFileName + bck_ext[i];
                            if (File.Exists(af))
                            {
                                archiveFileName = af;
                                break;
                            }
                            i--;
                        }

                        if (i < 0)
                        {
                            archiveFileName += bck_ext[2];
                        }


                        bool bHaveToBackup;
                        switch (config.FileSelectionMethod)
                        {
                            case FileSelectionMethod.ArchiveAttribute:
                                bHaveToBackup = (f.Attributes & FileAttributes.Archive) == FileAttributes.Archive;
                                break;

                            case FileSelectionMethod.Newer:
                                bHaveToBackup = !File.Exists(archiveFileName) || f.LastWriteTime > File.GetLastWriteTime(archiveFileName);
                                break;

                            default:
                                bHaveToBackup = true;
                                break;
                        }


                        if (bHaveToBackup)
                        {
                            using (var a = new FileArchiver(archiveFileName, this.ProgressAsync))
                            {
                                if (a.AddRevision(current.FullName))
                                {
                                    g_nCount++;
                                    IncrementDict(dictBackupedExtensions, ext);
                                }
                                else if (config.FileSelectionMethod == FileSelectionMethod.Newer)
                                {
                                    a.SetLastWriteTime(DateTime.Now);
                                }

                                if (config.CleareArchiveFlag)
                                {
                                    f.Attributes &= ~FileAttributes.Archive;
                                }

                                //a.Dispose();
                            }
                        }

                    }

                }
                catch (UnauthorizedAccessException)
                {
                    ;
                }
                catch (BreakProcessException)
                {
                    e.Cancel = true;
                    break;
                }
                catch (Exception exc)
                {
                    Debug.WriteLine("Error " + currentFile + " " + exc.Message);
                    MessageBox.Show("Pri spracovaní súboru " + currentFile + " nastala chyba \n\n" + exc.Message);
                    errorlist.Add(new KeyValuePair<string, string>(currentFile, exc.Message));
                }
            }

            var sbOutput = new StringBuilder();

            sbOutput.AppendFormat("{0:hh\\:mm\\:ss} {1}/{2}{3}\r\n", DateTime.Now - g_dtStart, g_nCount, g_nTotalCount, (e.Cancel ? " Canceled!!!" : ""));
            WriteStatistics(sbOutput, "Included", dictIncludedExtensions);
            WriteStatistics(sbOutput, "Excluded", dictExcludedExtensions);
            WriteStatistics(sbOutput, "Backuped", dictBackupedExtensions);

            if (errorlist.Count > 0)
            {
                sbOutput.Append("\r\nErrors:");
                foreach (var s in errorlist)
                {
                    sbOutput.AppendFormat("\r\n {0} {1}", s.Key, s.Value);
                }
            }

            var syspath = Path.Combine(config.DestPath, ".Bck7z");
            if (!Directory.Exists(syspath))
            {
                DirectoryInfo di = Directory.CreateDirectory(syspath);
                di.Attributes = FileAttributes.Directory | FileAttributes.Hidden;
            }

            var protocol = string.Format("{0}\\protocol{1:yyyyMMdd-HHmmss}.txt", syspath, DateTime.Now);
            File.WriteAllText(protocol, sbOutput.ToString());
            Process.Start(protocol);

            toolStripStatusLabel1.Text = string.Format(@"{0:hh\:mm\:ss} {1}/{2}", DateTime.Now - g_dtStart, g_nCount, g_nTotalCount);
            toolStripStatusLabel2.Text = string.Empty;

        }

        private void backgroundWorker1_DoWork_Convert(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            WSArchiveConfig config = (WSArchiveConfig)e.Argument;

            var directoryQueue = new Queue<DirectoryInfo>();

            directoryQueue.Enqueue(new DirectoryInfo(config.DestPath));

            var nextOutputTime = DateTime.Now;

            while (directoryQueue.Count > 0)
            {
                var current = directoryQueue.Dequeue();
                try
                {
                    foreach (var d in current.GetDirectories())
                    {
                        directoryQueue.Enqueue(d);
                    }

                    if (worker.CancellationPending)
                    {
                        e.Cancel = true;
                        break;
                    }

                    foreach (var f in current.GetFiles("*.bck*").Where(s => s.Extension.ToLower() == ".bck" || s.Extension.ToLower() == ".bck7z"))
                    {

                        if (worker.CancellationPending)
                        {
                            e.Cancel = true;
                            break;
                        }

                        g_nTotalCount++;
                        g_nCount++;

                        currentFile = f.FullName;

                        if (DateTime.Now >= nextOutputTime)
                        {
                            ProgressAsync(string.Empty);
                            nextOutputTime = nextOutputTime.AddMilliseconds(250);
                        }

                        using (var a = new FileArchiver(currentFile, this.ProgressAsync))
                        {
                            a.Upgrade();
                        }

                    }

                }
                catch (UnauthorizedAccessException)
                {
                    ;
                }
                catch (BreakProcessException)
                {
                    e.Cancel = true;
                    break;
                }
                catch (Exception exc)
                {
                    Debug.WriteLine("Error " + currentFile + " " + exc.Message);
                    MessageBox.Show("Pri spracovaní súboru " + currentFile + " nastala chyba \n\n" + exc.Message);
                }
            }

            var sbOutput = new StringBuilder();

            sbOutput.AppendFormat("{0:hh\\:mm\\:ss} {1}/{2}{3}\r\n", DateTime.Now - g_dtStart, g_nCount, g_nTotalCount, (e.Cancel ? " Canceled!!!" : ""));

            var syspath = Path.Combine(config.DestPath, ".Bck7z");
            if (!Directory.Exists(syspath))
            {
                DirectoryInfo di = Directory.CreateDirectory(syspath);
                di.Attributes = FileAttributes.Directory | FileAttributes.Hidden;
            }

            var protocol = string.Format("{0}\\protocol{1:yyyyMMdd-HHmmss}.txt", syspath, DateTime.Now);
            File.WriteAllText(protocol, sbOutput.ToString());
            Process.Start(protocol);

            toolStripStatusLabel1.Text = string.Format(@"{0:hh\:mm\:ss} {1}/{2}", DateTime.Now - g_dtStart, g_nCount, g_nTotalCount);
            toolStripStatusLabel2.Text = string.Empty;

        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

            progressForm.Close();
            progressForm.Dispose();
            progressForm = null;

            InitImages();
            ReadFolder();

            backgroundWorker1.Dispose();
            backgroundWorker1 = null;

        }

        private string ConvertDstPathToSrc(FileListViewItem fi)
        {
            var sDest = fi.FileName;
            if (!sDest.StartsWith(SelectedDstPath, StringComparison.InvariantCultureIgnoreCase))
            {
                throw new Exception("Path is wrong");
            }
            var relative = sDest.Substring(SelectedDstPath.Length);
            if (!fi.IsDirectory)
            {
                var iPos = relative.LastIndexOf('.');
                relative = relative.Substring(0, iPos);
            }
            return SelectedSrcPath + relative;
        }

        private void FillPaths()
        {
            cmbArchive.Items.Clear();
            foreach (var path in settings.Paths)
            {
                cmbArchive.Items.Add(path);
                if (path.Name == settings.LastArchive)
                    cmbArchive.SelectedItem = path;
            }
        }

        private bool ProgressAsync(string message)
        {
            return (bool)this.Invoke(new OnProgress(ProgressSync), message);
        }

        private bool ProgressSync(string message)
        {

            progressForm.MessageTime = string.Format(@"{0:hh\:mm\:ss}", DateTime.Now - g_dtStart);
            progressForm.MessageCounter = string.Format(@"{0}/{1}", g_nCount, g_nTotalCount);
            progressForm.MessageInfo = message;
            progressForm.MessageFile = currentFile;

            //Application.DoEvents();

            if (backgroundWorker1.CancellationPending)
            {
                return false;
            }

            return true;
        }

        private void miExploreDstFile_Click(object sender, EventArgs e)
        {
            if (listViewFiles.SelectedItems.Count > 0)
            {
                var fi = listViewFiles.SelectedItems[0].Tag as FileListViewItem;
                if (fi.IsDirectory)
                    Process.Start("explorer.exe", fi.FileName);
                else
                    Process.Start("explorer.exe", @"/select, " + fi.FileName);
            }
        }

        private void miExploreSrcFile_Click(object sender, EventArgs e)
        {
            var fi = listViewFiles.SelectedItems[0].Tag as FileListViewItem;
            if (fi.IsDirectory)
                Process.Start("explorer.exe", ConvertDstPathToSrc(fi));
            else
                Process.Start("explorer.exe", @"/select, " + ConvertDstPathToSrc(fi));
        }

        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            if (listViewFiles.SelectedItems.Count != 1)
            {
                e.Cancel = true;
                return;
            }
            var fi = listViewFiles.SelectedItems[0].Tag as FileListViewItem;
            miShowRevisions.Visible = !fi.IsDirectory;
        }

        private void miShowRevisions_Click(object sender, EventArgs e)
        {
            if (listViewFiles.SelectedItems.Count == 1)
            {
                var fi = listViewFiles.SelectedItems[0].Tag as FileListViewItem;
                if (!fi.IsDirectory)
                {
                    new FormRevisions(settings, SelectedSrcPath, fi.FileName).ShowDialog(this);
                }
            }
        }

        private int NeedConversion()
        {
            if (currentPath == null)
            {
                MessageBox.Show("Zvolte adresár");
                throw new Exception();
            }

            Cursor = Cursors.WaitCursor;

            var ret = 0;

            var directoryQueue = new Queue<DirectoryInfo>();

            directoryQueue.Enqueue(new DirectoryInfo(currentPath.DestPath));

            while (directoryQueue.Count > 0)
            {
                var current = directoryQueue.Dequeue();

                foreach (var d in current.GetDirectories())
                {
                    directoryQueue.Enqueue(d);
                }

                ret += current.GetFiles("*.bck*").Select(s => s.Extension.ToLower()).Where(s => s == ".bck" || s == ".bck7z").Count();

            }

            Cursor = Cursors.Default;

            return ret;
        }

    }
}
